/*
 * 缓冲区模块
 *
 * 定义一个队列缓冲区，扩容、尾插和头取。
 *
 **/

#pragma once

#include <vector>
#include <utility>

namespace easylog
{
    template<class value>
    class ring_queue
    {
    public:
        using self = ring_queue<value>;

    public:
        ring_queue(size_t size, size_t incr, size_t thres)
            : _buf(size + 1)
            , _cap(size)
            , _increment(incr)
            , _threshold(thres)
            , _rear(0)
            , _front(0)
        {}

        void set_size(size_t cap) { _cap = cap; }

        void set_incrment(size_t incr) { _increment = incr; }

        void set_threshold(size_t thres) { _threshold = thres; }

        void push(value&& in)
        {
            _buf[_rear++] = std::forward<value>(in);
            _rear %= _cap + 1;
        }

        void pop(value& out)
        {
            out = std::move(_buf[_front++]);
            _front %= _cap + 1;
        }

        size_t size()
        {
            return (_rear -_front + _cap + 1) % (_cap + 1);
        }

        bool wrable()
        {
            return !((_rear + 1) % (_cap + 1) == _front);
        }

        bool rdable()
        {
            return !(_rear == _front);
        }

        void reserve()
        {
            size_t incr = 0;
            if (_cap < _threshold) incr = _cap * 2;
            else incr = _cap + _increment;

            _cap += incr;
            _buf.resize(_buf.size() + incr);
        }

        void swap(self& q)
        {
            _buf.swap(q._buf);
            std::swap(_cap, q._cap);
            std::swap(_increment, q._increment);
            std::swap(_threshold, q._threshold);
            std::swap(_rear, q._rear);
            std::swap(_front, q._front);
        }

    private:
        std::vector<value> _buf;
        size_t _cap;
        size_t _rear;
        size_t _front;
        size_t _increment;  // increment of expandsion
        size_t _threshold;  // threshold of expandsion
        // Before reaching the threshold, expand by twice,
        // after that, expand by the incremental size.
    };
}
